/*
  S.M.A.C.K - An operating system kernel
  Copyright (C) 2010,2011 Mattias Holm and Kristian Rietveld
  For licensing and a full list of authors of the kernel, see the files
  COPYING and AUTHORS.
*/

/*!
  \file bittools.h
  Common and useful bit manipulation functions. Most of these will be inline functions for speed reasons.
*/
#ifndef KERNEL__BITTOOLS_H
#define KERNEL__BITTOOLS_H
#include <stdint.h>
#include <stdbool.h>

// NOTE: Using intrinsics for the ctz and clz is dependent on gcc

/*!
  Count Trailing Zeroes 32
  \asyncsafe
*/
static inline int
ctz_32(uint32_t a)
{
  return __builtin_ctz(a);
}

/*!
  Count Leading Zeroes 32
  \asyncsafe
*/
static inline int
clz_32(uint32_t a)
{
  return __builtin_clz(a);
}

/*!
  Count Trailing Ones 32
  \asyncsafe
*/
static inline int
cto_32(uint32_t a)
{
  return __builtin_ctz(~a);
}

/*!
  Count Leading Ones 32
  \asyncsafe
*/
static inline int
clo_32(uint32_t a)
{
  return __builtin_clz(~a);
}

/*!
  Count Trailing Ones 64
  \asyncsafe
*/
static inline int
cto_64(uint64_t a)
{
  return __builtin_ctzll(~a);
}

/*!
  Count Leading Ones 64
  \asyncsafe
*/
static inline int
clo_64(uint64_t a)
{
  return __builtin_ctzll(~a);
}


/*!
  Floor to power of 2, 32 bit version
  Based on Hackers Delight p47
  \asyncsafe
*/
static inline uint32_t
flp2_32(uint32_t x)
{
  x = x | (x >> 1);
  x = x | (x >> 2);
  x = x | (x >> 4);
  x = x | (x >> 8);
  x = x | (x >> 16);
  return x - (x >> 1);
}

/*!
  Closest power of 2, 32 bit version
  Based on Hackers Delight p48, rounds up to closest power of 2
  \asyncsafe
*/
static inline uint32_t
clp2_32(uint32_t x)
{
  x = x - 1;
  x = x | (x >> 1);
  x = x | (x >> 2);
  x = x | (x >> 4);
  x = x | (x >> 8);
  x = x | (x >> 16);
  return x + 1;
}

/*!
  Align to power of 2 boundary, 32 bit version

  Aligns the given value upwards so that the address is congruent with
  x' = 0 (mod align).

  \param x value to round
  \param align Power of 2 sized alignment value
  \asyncsafe
*/
static inline uint32_t
align_32(uint32_t x, uint32_t align)
{
  return (x + align - 1) & -align;
}

static inline uint64_t
align_64(uint64_t x, uint64_t align)
{
  return (x + align - 1) & -align;
}

static inline pa_t
align_pa(pa_t x, pa_t align)
{
  return (x + align - 1) & -align;
}

static inline va_t
align_va(va_t x, va_t align)
{
  return (x + align - 1) & -align;
}

/*!
  Predicate for power of 2 checking, 32 bit version.
  \asyncsafe
 */
static inline bool
is_pow2_32(uint32_t x)
{
  return ((x & (x-1)) == 0) && (x != 0);
}

/*!
  Predicate for power of 2 checking, 64 bit version.
  \asyncsafe
 */
static inline bool
is_pow2_64(uint64_t x)
{
  return ((x & (x-1)) == 0) && (x != 0);
}

/*!
  Predicate for power of 2 checking, virtual address version.
  \asyncsafe
 */
static inline bool
is_pow2_va(va_t x)
{
  return ((x & (x-1)) == 0) && (x != 0);
}

/*!
  Predicate for power of 2 checking, physical address version.
  \asyncsafe
 */
static inline bool
is_pow2_pa(pa_t x)
{
  return ((x & (x-1)) == 0) && (x != 0);
}


#endif /* !KERNEL__BITTOOLS_H */
